package cn.stacey.day13;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Serverfx1 extends Application{
	private TextArea ta;
	public static void main(String[] args) {
		launch(args);
		// 下面的没有放到try()里关闭，而是放在finally里面关闭，是因为输入输出流放在try中就执行不到下面的输入输出
//		InputStream in = null;

		
		
		


	}

	@Override
	public void start(Stage primaryStage) throws Exception {
		// TODO Auto-generated method stub
		VBox box=new VBox(10);
		box.setPadding(new Insets(10));
		//多行输入TextARea
		TextArea ta=new TextArea();
		box.getChildren().add(ta);
		VBox.setVgrow(ta, Priority.ALWAYS);
		Scene scene=new Scene(box,500,400);
		primaryStage.setScene(scene);
		primaryStage.show();
		//必须开启异步线程去打开socket，否则socket.accept()会阻塞ui线程，程序界面就没有反应
		//如果不加下面这句话，场景的弹框就一直弹不出来
		new Thread(() -> {
			openSocket();
			}).start() ;
		
	}
	//添加消息到对话框
	public void appendMessage(String message) {
		ta.appendText(message+"\n");
	}
	//服务器开启线程
	public void openSocket() {
		ServerSocket server=null;		
		try {

			// 端口不能用1024以下
			server = new ServerSocket(6666);
			// socket代表连接上的客户端
			// 如果有客户端连接，会返回一个socket对象，
			// 如果没有连接，accept就会让当前的线程处于阻塞状态

			// Server3    多个客户端与服务器连接的实现，
			// 如果多次写accept会发生阻塞，所以将reader通信交给另一线程，异步通信


			// 开始通信
			// 服务器读取客户端发来的消息
			// in=socket.getInputStream();
			// 当服务器只发来一个字符，而在下面in.read()有两个的情况下，后面一个in.read()会处于等待下一个的状态
			// System.out.println(in.read());
			// System.out.println(in.read());

			// 让服务器不断的去读，用循环

			// while(true) {
			// char read=(char)in.read();
			// System.out.println(read);
			// if(read=='8') {
			// break;
			// }
			// }


			// 启动异步线程
			// 需要开启很多客户端与服务器端进行通信，可以用while循环
			// 因为每次运行一个客户端，都必须开启一次.accept还要开启一个线程(new Thread())
			// new Thread(new ThreadClient(socket)).start();
			// socket=server.accept();
			// new Thread(new ThreadClient(socket)).start();
			while (true) {
				Socket socket = server.accept();
				//不懂下面为何这样修改？？
//				new Thread(new ThreadSocket(socket)).start();
				//注意下面Serverfx1.this用法
				//类名.this一般用于内部类，表示那个类名所代表的类的对象
				new Thread(new ThreadSocket(Serverfx1.this,socket)).start();
				System.out.println("连上了一个客户端连接" + "客户端IP" + socket.getInetAddress() + "客户端端口" + socket.getPort());

			}

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			// 要关闭in out socket server 需要写四次try catch 所以调用下面的方法closeQuitely(Closeable c)
			// 要先关闭in和Out 再关闭socket 最后关闭server

//			UtilsClose.closeQuitely(out);

			UtilsClose.closeQuitely(server);
		}
	}
}


// 对象拆分需要通过构造器来传递需要的参数

class ThreadSocket implements Runnable {
	private DataInputStream in;
	private Socket socket;
	private Serverfx1 serverfx1;
//为何此下面的构造器传入Serverfx1 serverfx1？？(这样可以在Serverfx1类中开启线程？)
//	public ThreadSocket(Socket socket) {
	public ThreadSocket(Serverfx1 sercerfx1,Socket socket) {
		this.socket = socket;
		this.serverfx1=sercerfx1;
	}



	@Override
	public void run() {
		// TODO Auto-generated method stub

		try {
//			in = socket.getInputStream();
			in=new DataInputStream(new BufferedInputStream(socket.getInputStream()));
			// char read = (char) in.read();这句话放在本行，会不停的读客户端传来的消息
			while (true) {
//				char read = (char) in.read();
				String message=in.readUTF();
				//???会报错51行和下面这句话空指针异常
				serverfx1.appendMessage(message);
				
//				System.out.println(message);
				if ("886".equals(message)) {
					break;
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			UtilsClose.closeQuitely(in);
			UtilsClose.closeQuitely(socket);
		}
	}

}
